home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / alpha.arc / TCPUSER.C < prev    next >
C/C++ Source or Header  |  1988-07-21  |  7KB  |  339 lines

  1. /* User calls to TCP */
  2. #include "global.h"
  3. #include "timer.h"
  4. #include "mbuf.h"
  5. #include "netuser.h"
  6. #include "internet.h"
  7. #include "tcp.h"
  8.  
  9. int16 tcp_window = DEF_WND;
  10.  
  11. struct tcb *
  12. open_tcp(lsocket,fsocket,mode,window,r_upcall,t_upcall,s_upcall,tos,user)
  13. struct socket *lsocket;    /* Local socket */
  14. struct socket *fsocket;    /* Remote socket */
  15. int mode;        /* Active/passive/server */
  16. int16 window;        /* Receive window (and send buffer) sizes */
  17. void (*r_upcall)();    /* Function to call when data arrives */
  18. void (*t_upcall)();    /* Function to call when ok to send more data */
  19. void (*s_upcall)();    /* Function to call when connection state changes */
  20. char tos;
  21. char *user;        /* User linkage area */
  22. {
  23.     struct connection conn;
  24.     register struct tcb *tcb;
  25.     void send_syn();
  26.  
  27.     if(lsocket == NULLSOCK){
  28.         net_error = INVALID;
  29.         return NULLTCB;
  30.     }
  31.     conn.local.address = lsocket->address;
  32.     conn.local.port = lsocket->port;
  33.     if(fsocket != NULLSOCK){
  34.         conn.remote.address = fsocket->address;
  35.         conn.remote.port = fsocket->port;
  36.     } else {
  37.         conn.remote.address = 0;
  38.         conn.remote.port = 0;
  39.     }
  40.     if((tcb = lookup_tcb(&conn)) == NULLTCB){
  41.         if((tcb = create_tcb(&conn)) == NULLTCB){
  42.             net_error = NO_SPACE;
  43.             return NULLTCB;
  44.         }
  45.     } else if(tcb->state != LISTEN){
  46.         net_error = CON_EXISTS;
  47.         return NULLTCB;
  48.     }
  49.     tcb->user = user;
  50.     if(window != 0)
  51.         tcb->window = tcb->rcv.wnd = window;
  52.     else
  53.         tcb->window = tcb->rcv.wnd = tcp_window;
  54.     tcb->r_upcall = r_upcall;
  55.     tcb->t_upcall = t_upcall;
  56.     tcb->s_upcall = s_upcall;
  57.     tcb->tos = tos;
  58.     switch(mode){
  59.     case TCP_SERVER:
  60.         tcb->flags |= CLONE;
  61.     case TCP_PASSIVE:    /* Note fall-thru */
  62.         setstate(tcb,LISTEN);
  63.         break;
  64.     case TCP_ACTIVE:
  65.         /* Send SYN, go into SYN_SENT state */
  66.         tcb->flags |= ACTIVE;
  67.         send_syn(tcb);
  68.         setstate(tcb,SYN_SENT);
  69.         tcp_output(tcb);
  70.         tcp_stat.conout++;
  71.         break;
  72.     }
  73.     return tcb;
  74. }
  75. /* User send routine */
  76. int
  77. send_tcp(tcb,bp)
  78. register struct tcb *tcb;
  79. struct mbuf *bp;
  80. {
  81.     int16 cnt;
  82.     void send_syn();
  83.  
  84.     if(tcb == NULLTCB || bp == NULLBUF){
  85.         free_p(bp);
  86.         net_error = INVALID;
  87.         return -1;
  88.     }
  89.     cnt = len_mbuf(bp);
  90. #ifdef    TIGHT
  91.     /* If this would overfill our send queue, reject it entirely */
  92.     if(tcb->sndcnt + cnt > tcb->window){
  93.         free_p(bp);
  94.         net_error = WOULDBLK;
  95.         return -1;
  96.     }
  97. #endif
  98.     switch(tcb->state){
  99.     case CLOSED:
  100.         free_p(bp);
  101.         net_error = NO_CONN;
  102.         return -1;
  103.     case LISTEN:    /* Change state from passive to active */
  104.         tcb->flags |= ACTIVE;
  105.         send_syn(tcb);
  106.         setstate(tcb,SYN_SENT);    /* Note fall-thru */
  107.     case SYN_SENT:
  108.     case SYN_RECEIVED:
  109.     case ESTABLISHED:
  110.     case CLOSE_WAIT:
  111.         append(&tcb->sndq,bp);
  112.         tcb->sndcnt += cnt;
  113.         tcp_output(tcb);
  114.         break;
  115.     case FINWAIT1:
  116.     case FINWAIT2:
  117.     case CLOSING:
  118.     case LAST_ACK:
  119.     case TIME_WAIT:
  120.         free_p(bp);
  121.         net_error = CON_CLOS;
  122.         return -1;
  123.     }
  124.     return cnt;
  125. }
  126. /* User receive routine */
  127. int
  128. recv_tcp(tcb,bp,cnt)
  129. register struct tcb *tcb;
  130. struct mbuf **bp;
  131. int16 cnt;
  132. {
  133.     if(tcb == NULLTCB || bp == (struct mbuf **)NULL){
  134.         net_error = INVALID;
  135.         return -1;
  136.     }
  137.     /* cnt == 0 means "I want it all" */
  138.     if(cnt == 0)
  139.         cnt = tcb->rcvcnt;
  140.     /* If there's something on the queue, just return it regardless
  141.      * of the state we're in.
  142.      */
  143.     if(tcb->rcvcnt != 0){
  144.         /* See if the user can take all of it */
  145.         if(tcb->rcvcnt <= cnt){
  146.             cnt = tcb->rcvcnt;
  147.             *bp = tcb->rcvq;
  148.             tcb->rcvq = NULLBUF;
  149.         } else {
  150.             if((*bp = alloc_mbuf(cnt)) == NULLBUF){
  151.                 net_error = NO_SPACE;
  152.                 return -1;
  153.             }
  154.             pullup(&tcb->rcvq,(*bp)->data,cnt);
  155.             (*bp)->cnt = cnt;
  156.         }
  157.         tcb->rcvcnt -= cnt;
  158.         tcb->rcv.wnd += cnt;
  159.         /* Do a window update if it was closed */
  160.         if(cnt == tcb->rcv.wnd){
  161.             tcb->flags |= FORCE;
  162.             tcp_output(tcb);
  163.         }
  164.         return cnt;
  165.     } else {
  166.         /* If there's nothing on the queue, our action depends on what state
  167.          * we're in (i.e., whether or not we're expecting any more data).
  168.          * If no more data is expected, then simply return 0; this is
  169.          * interpreted as "end of file".
  170.          */
  171.         switch(tcb->state){
  172.         case LISTEN:
  173.         case SYN_SENT:
  174.         case SYN_RECEIVED:
  175.         case ESTABLISHED:
  176.         case FINWAIT1:
  177.         case FINWAIT2:
  178.             *bp = NULLBUF;
  179.             net_error = WOULDBLK;
  180.             return -1;
  181.         case CLOSED:
  182.         case CLOSE_WAIT:
  183.         case CLOSING:
  184.         case LAST_ACK:
  185.         case TIME_WAIT:
  186.             *bp = NULLBUF;
  187.             return 0;
  188.         }
  189.     }
  190.     return 0;    /* Not reached, but lint doesn't know that */
  191. }
  192. /* This really means "I have no more data to send". It only closes the
  193.  * connection in one direction, and we can continue to receive data
  194.  * indefinitely.
  195.  */
  196. int
  197. close_tcp(tcb)
  198. register struct tcb *tcb;
  199. {
  200.     if(tcb == NULLTCB){
  201.         net_error = INVALID;
  202.         return -1;
  203.     }
  204.     switch(tcb->state){
  205.     case LISTEN:
  206.     case SYN_SENT:
  207.         close_self(tcb,NORMAL);
  208.         return 0;
  209.     case SYN_RECEIVED:
  210.     case ESTABLISHED:
  211.         tcb->sndcnt++;
  212.         tcb->snd.nxt++;
  213.         setstate(tcb,FINWAIT1);
  214.         tcp_output(tcb);
  215.         return 0;
  216.     case CLOSE_WAIT:
  217.         tcb->sndcnt++;
  218.         tcb->snd.nxt++;
  219.         setstate(tcb,LAST_ACK);
  220.         tcp_output(tcb);
  221.         return 0;
  222.     case FINWAIT1:
  223.     case FINWAIT2:
  224.     case CLOSING:
  225.     case LAST_ACK:
  226.     case TIME_WAIT:
  227.         net_error = CON_CLOS;
  228.         return -1;
  229.     }
  230.     return -1;    /* "Can't happen" */
  231. }
  232. /* Delete TCB, free resources. The user is not notified, even if the TCB is
  233.  * not in the CLOSED state. This function should normally be called by the
  234.  * user only in response to a state change upcall to CLOSED state.
  235.  */
  236. int
  237. del_tcp(tcb)
  238. register struct tcb *tcb;
  239. {
  240.     void unlink_tcb();
  241.     struct reseq *rp,*rp1;
  242.  
  243.     if(tcb == NULLTCB){
  244.         net_error = INVALID;
  245.         return -1;
  246.     }
  247.     unlink_tcb(tcb);
  248.     stop_timer(&tcb->timer);
  249.     stop_timer(&tcb->rtt_timer);
  250.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  251.         rp1 = rp->next;
  252.         free_p(rp->bp);
  253.         free((char *)rp);
  254.     }
  255.     tcb->reseq = NULLRESEQ;
  256.     free_p(tcb->rcvq);
  257.     free_p(tcb->sndq);
  258.     free((char *)tcb);
  259.     return 0;
  260. }
  261. /* Do printf on a tcp connection */
  262. /*VARARGS*/
  263. tprintf(tcb,message,arg1,arg2,arg3)
  264. struct tcb *tcb;
  265. char *message,*arg1,*arg2,*arg3;
  266. {
  267.     struct mbuf *bp;
  268.     int len;
  269.  
  270.     if(tcb == NULLTCB)
  271.         return 0;
  272.  
  273.     bp = alloc_mbuf(100);
  274.     len = sprintf(bp->data,message,arg1,arg2,arg3);
  275.     bp->cnt = strlen(bp->data);
  276.     send_tcp(tcb,bp);
  277.     return len;
  278. }
  279. /* Return 1 if arg is a valid TCB, 0 otherwise */
  280. int
  281. tcpval(tcb)
  282. struct tcb *tcb;
  283. {
  284.     register int i;
  285.     register struct tcb *tcb1;
  286.  
  287.     if(tcb == NULLTCB)
  288.         return 0;    /* Null pointer can't be valid */
  289.     for(i=0;i<NTCB;i++){
  290.         for(tcb1=tcbs[i];tcb1 != NULLTCB;tcb1 = tcb1->next){
  291.             if(tcb1 == tcb)
  292.                 return 1;
  293.         }
  294.     }
  295.     return 0;
  296. }
  297. kick_tcp(tcb)
  298. register struct tcb *tcb;
  299. {
  300.     void tcp_timeout();
  301.  
  302.     if(!tcpval(tcb))
  303.         return -1;
  304.     tcp_timeout((char *)tcb);
  305.     return 0;
  306. }
  307. reset_tcp(tcb)
  308. register struct tcb *tcb;
  309. {
  310.     close_self(tcb,RESET);
  311. }
  312. /* Return character string corresponding to a TCP well-known port, or
  313.  * the decimal number if unknown.
  314.  */
  315. char *
  316. tcp_port(n)
  317. int16 n;
  318. {
  319.     static char buf[32];
  320.  
  321.     switch(n){
  322.     case ECHO_PORT:
  323.         return "echo";
  324.     case DISCARD_PORT:
  325.         return "discard";
  326.     case FTPD_PORT:
  327.         return "ftp_data";
  328.     case FTP_PORT:
  329.         return "ftp";    
  330.     case TELNET_PORT:
  331.         return "telnet";
  332.     case SMTP_PORT:
  333.         return "smtp";
  334.     default:
  335.         sprintf(buf,"%u",n);
  336.         return buf;
  337.     }
  338. }
  339.